package controller;

import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;

import model.CityTrafficModel;
import model.Distance;
import model.Speed;
import model.Time;

/**
 * @author samuel
 * 
 */
public class TrafficCalculator {

	/**
	 * @param currentTime
	 * @param period
	 * @return
	 */
	public static boolean isLightRed(Time currentTime, Time period) {
		boolean isRed = false;
		double elapsedSecond = currentTime.getFloredTimeInSecond();
		double periodInSecond = period.getFloredTimeInSecond();

		Double fractionOFPy = (Math.PI) * (elapsedSecond / periodInSecond);
		Float sinResult = new Float(Math.sin(fractionOFPy));

		double epsilon = 0.00000001;

		if (sinResult < epsilon) {
			isRed = true;
		}

		return isRed;
	}

	/**
	 * @param currentTime
	 * @param period
	 * @return
	 */
	public static Time calculateRemainingRedTime(Time currentTime, Time period) {

		int periodInSecond = period.getFloredTimeInSecond();
		int currentTimeInSecond = currentTime.getFloredTimeInSecond();

		if (currentTimeInSecond == 0) {
			return Time.makeTimeFromSecond(0);
		}

		int restInSecond = currentTimeInSecond % periodInSecond;

		if (restInSecond == 0) {
			int isPairResult = ((currentTimeInSecond / periodInSecond) % 2);
			if (isPairResult != 0) {
				return period;
			}
		}

		return Time.makeTimeFromSecond(periodInSecond - restInSecond);
	}

	/**
	 * @param currentTime
	 * @param period
	 * @param model
	 * @return
	 */
	public static Time getNexElapsedTime(Time currentTime, Time period,
			CityTrafficModel model) {
		Logger logger = Logger.getLogger("TrafficCalculator");

		Time elapsedTime = Time.makeTimeFromSecond(0);

		Time waitingTime = Time.makeTimeFromSecond(0);

		if (isLightRed(currentTime, period)) {

			logger.log(
					Level.INFO,
					" The car reach the next red light at time ="
							+ currentTime.getFloredTimeInSecond() + "s");
			waitingTime = calculateRemainingRedTime(currentTime, period);
			logger.log(Level.INFO, " The light is red, the waiting time = "
					+ waitingTime.getFloredTimeInSecond() + "s");

		} else {
			logger.log(Level.INFO,
					" The light is still green and the car drives on through");
		}

		Time travelTime = calculateElapsedTime(model.getCarSpeed(),
				model.getDistanceBetweenLights());

		elapsedTime = waitingTime.addTime(travelTime);

		return elapsedTime;
	}

	/**
	 * @param model
	 * @return
	 */
	public static Time calculateTimeTravel(CityTrafficModel model) {
		Logger logger = Logger.getLogger("TrafficCalculator");

		Time currentTime = Time.makeTimeFromSecond(0);

		Collection<Time> times = model.getTimeBetweenSignalChanges();

		Distance initialDistance = model.getInitialCarDistance();

		currentTime = calculateElapsedTime(model.getCarSpeed(), initialDistance);
		System.out.println();
		logger.log(Level.INFO,
				"The car reaches the First Traffic light at time ="
						+ currentTime.getFloredTimeInSecond() + "s");
		for (Time time : times) {
			Time nextGreenTime = getNexElapsedTime(currentTime, time, model);
			currentTime = currentTime.addTime(nextGreenTime);
		}

		logger.log(Level.INFO,
				"At time =:" + currentTime.getFloredTimeInSecond()
						+ "s the car reaches the end,"
						+ model.getDistanceBetweenLights().getDistanceInMeter()
						+ " meters pass the last traffic light");

		return currentTime;
	}

	/**
	 * @param speed
	 * @param distance
	 * @return
	 */
	public static Time calculateElapsedTime(Speed speed, Distance distance) {
		float timeInSecond = (float) distance.getDistanceInMeter()
				/ (float) speed.getMeterPerSecond();
		return Time.makeTimeFromSecond(timeInSecond);
	}
}
